#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include "ArduinoJson.h"
#include "SSD1306Wire.h"
SSD1306Wire display(0x3c,2,14);

#include "dht11.h"
dht11 DHT11;
#define DHT11PIN 5
// 设置wifi接入信息(请根据您的WiFi信息进行修改)
const char* ssid = "帅气杰少";
const char* password = "314314sqjs";
const char* mqttServer = "121.40.91.87";

const uint8_t R_port = 12;
const uint8_t G_port = 13;
const uint8_t B_port = 15;
 
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
 
void setup() {
  pinMode(R_port, OUTPUT);     // 设置板上LED引脚为输出模式
  pinMode(G_port, OUTPUT);
  pinMode(B_port, OUTPUT);
  pinMode(5,OUTPUT);
  Serial.begin(115200);               // 启动串口通讯
  display.init();
  //设置ESP8266工作模式为无线终端模式
  WiFi.mode(WIFI_STA);
  
  // 连接WiFi
  connectWifi();
  
  // 设置MQTT服务器和端口号
  mqttClient.setServer(mqttServer, 1883);
  mqttClient.setCallback(receiveCallback);
 
  // 连接MQTT服务器
  connectMQTTserver();
}
 
void loop() {
  if (mqttClient.connected()) { // 如果开发板成功连接服务器
    mqttClient.loop();// 处理信息以及心跳
    pubTopic();//发布消息
  } else {                      // 如果开发板未能成功连接服务器
    connectMQTTserver();        // 则尝试连接服务器
  }
}
 
// 连接MQTT服务器并订阅信息
void connectMQTTserver(){
  
  String clientId = "HJX_ESP8266";
 
  // 连接MQTT服务器
  if (mqttClient.connect(clientId.c_str())) { 
    Serial.println("MQTT Server Connected.");
    Serial.println("Server Address:");
    Serial.println(mqttServer);
    Serial.println("ClientId: ");
    Serial.println(clientId);
    subscribeTopic(); // 订阅指定主题
  } else {
    Serial.print("MQTT Server Connect Failed. Client State:");
    Serial.println(mqttClient.state());
    delay(5000);
  }   
}

void pubTopic(){
  DHT11.read(DHT11PIN);//读取温湿度
  
  String topic_esp = "ZUCC-HJX/esp";

  char subTopic_esp[topic_esp.length() + 1];  
  strcpy(subTopic_esp, topic_esp.c_str());
  
  StaticJsonDocument<200> doc; //初始化一个json的对象

  doc["hum"] = (float)DHT11.humidity;
  doc["temp"] = (float)DHT11.temperature;
  // 反序列化为 string
  String output;
  serializeJson(doc ,output);
  mqttClient.publish(subTopic_esp,output.c_str());
  delay(2000);
}
// 收到信息后的回调函数
void receiveCallback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message Received [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println("");
  Serial.print("Message Length(Bytes) ");
  Serial.println(length);

  String topic_oled = "ZUCC-HJX/oled";
  String topic_rgb = "ZUCC-HJX/rgb";


  String tt = String(topic);
  char subTopic_oled[topic_oled.length() + 1];  
  strcpy(subTopic_oled, topic_oled.c_str());

  char subTopic_rgb[topic_rgb.length() + 1];  
  strcpy(subTopic_rgb, topic_rgb.c_str());
  
  
  DynamicJsonDocument doc(1024);
  deserializeJson(doc,payload);
  JsonObject obj = doc.as<JsonObject>();
  if(tt==subTopic_oled)
  {
    String msg =obj["msg"].as<String>();
    display.clear();
    display.setTextAlignment(TEXT_ALIGN_LEFT);
    display.setFont(ArialMT_Plain_16);
    display.drawString(8,0,msg);
    display.drawString(8, 18, "Temp:");
      display.drawString(58, 18, (String)DHT11.temperature);
      display.drawString(8, 38, "Hum:");
      display.drawString(58, 38, (String)DHT11.humidity);
    display.display();
    delay(500);
  }
  if(tt==subTopic_rgb)
  {
    int R_num = obj["R"].as<int>();
    int G_num = obj["G"].as<int>();
    int B_num = obj["B"].as<int>();
    Serial.print(R_num);
    Serial.print(G_num);
    Serial.print(B_num);
    analogWrite(R_port,R_num);
    analogWrite(G_port,G_num);
    analogWrite(B_port,B_num);
   }
}
 
// 订阅指定主题
void subscribeTopic(){
 
  String topic_oled = "ZUCC-HJX/oled";
  String topic_rgb = "ZUCC-HJX/rgb";
  
  char subTopic_oled[topic_oled.length() + 1];  
  strcpy(subTopic_oled, topic_oled.c_str());

  char subTopic_rgb[topic_rgb.length() + 1];  
  strcpy(subTopic_rgb, topic_rgb.c_str());
  
  
  // 通过串口监视器输出是否成功订阅主题以及订阅的主题名称
  if(mqttClient.subscribe(subTopic_oled)){
    Serial.println("Subscrib Topic:");
    Serial.println(subTopic_oled);
  } else {
    Serial.print("Subscribe oled Fail...");
  }
  if(mqttClient.subscribe(subTopic_rgb)){
    Serial.println("Subscrib Topic:");
    Serial.println(subTopic_rgb);
  } else {
    Serial.print("Subscribe rgb Fail...");
  } 
}
 
// ESP8266连接wifi
void connectWifi(){
 
  WiFi.begin(ssid, password);
 
  //等待WiFi连接,成功连接后输出成功信息
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi Connected!");  
  Serial.println(""); 
}
